//
//  MainViewController.m
//  RunSketch
//
//  Created by Brian Hinch on 7/8/08.
//  Copyright Tellart 2008. All rights reserved.
//

#import "MainViewController.h"
#import "SketchUpdateController.h"
#import "MainView.h"
#import "SketchWebView.h"
#import "SketchProtocol.h"
#import "AM_IO.h"

@implementation MainViewController
@synthesize webView;
@synthesize am_io;


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
	if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
	}
    
    //doing this to make sure that these are chars

    skc_incomingMessageBufferSize = kSketchProtocol_longestPossibleMessageLength;
    skc_outgoingMessageBufferSize = kSketchProtocol_longestPossibleMessageLength;
    [self skc_allocMessageBuffer];
    
	serverFlowControlEnabled = 0;
	serverFlowControlWaitForSetUntil = 0;
	
    sketchServerName = NULL;
    [sketchServerName retain];
	retainedJavaScriptCall = NULL;
	[retainedJavaScriptCall retain];
	retainedSendValuesStr = NULL;
	[retainedSendValuesStr retain];
	skc_sketchPollingScanner = NULL;
	[skc_sketchPollingScanner retain];
    

    //Audio
    am_io = [[AM_IO alloc] init];
    [am_io retain];
	[am_io initAudio];    
    //id <PeakAmplitudeDelegate> mydelegate = self;
    //am_io.peakAmpDelegate = mydelegate;
    [[NSTimer scheduledTimerWithTimeInterval:.05 
      
                                      target:self
      
                                    selector:@selector(audioAmplitudeTimer:)
      
                                    userInfo:nil
      
                                     repeats:YES]
     
     retain];
    
    
    // Custom initialization
    NSLog(@"initWithNibName custom init");
    [self initWebView];
    
	return self;
} //initWithNibName

- (void)loadView {
    [super loadView];
}

- (void)initWebView {    
    NSLog(@"MainViewController: initWebView");
    
    //UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    UIView *contentView = self.view;
    
    //create a frame that will be used to size and place the web view
    CGRect webFrame = CGRectMake(0.0, 0.0, 320.0, 460.0);
    SketchWebView *aWebView = [[SketchWebView alloc] initWithFrame:webFrame];
    //set the web view delegate for the web view to be itself
    [aWebView setDelegate:self];
    self.webView = aWebView;
    [aWebView release];
    
    //add the web view to the content view
    [contentView addSubview:self.webView];
    
    
} //loadView

/* do more setup after the view loads
 - (void)viewDidLoad {
 }
 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"MainViewController: touchesBegan");
    [super touchesBegan:touches withEvent:event];
}

- (void)loadSketch {
    NSURL *aURL = [SketchUpdateController getSketchEntryPointURL];
    
    NSURLRequest *aRequest = [NSURLRequest requestWithURL:aURL];
    //load the index.html file into the web view.
    [webView loadRequest:aRequest];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	// Return YES for supported orientations
	return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void) closeDown {
	//DO NOT USE retainedJavaScriptCall HERE!!!
	NSString* javaScriptCall = @"document.getElementsByTagName('body')[0].onunload()";
	[webView stringByEvaluatingJavaScriptFromString:javaScriptCall];
	NSLog(@"closed");
}

- (void)didReceiveMemoryWarning {
	[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
	// Release anything that's not essential, such as cached data
}

/*******************************************************************************************************************/

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
	NSLog(@"webView: An error happened during load");
}
- (void)webViewDidStartLoad:(UIWebView *)webView{
	NSLog(@"webView: loading started");
    [self disableSensors];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
	NSLog(@"webView: finished loading");
    [self enableSensors];
}

/*******************************************************************************************************************/
- (void) disableSensors {
    NSLog(@"MainViewController: disabling sensors...");
    [self disableSensorLocation];
    [self disableSensorAccelerometer];
    [self disableSketchServer];
}
- (void) enableSensors {
    NSLog(@"MainViewController: enabling sensors...");
    [self enableSensorLocation];
    [self enableSensorAccelerometer];
    [self enableSketchServer];
}

/*******************************************************************************************************************/

// set up to receive notifications and send outputs to SketchServer
- (void)enableSketchServer {
    NSLog(@"MainViewController: enableSketchServer");
    if (sketchServerEnabled == 0) {

        //NSMutableData*  response;

        NSLog(@"MainViewController: enabling SketchServer connection");

        // Create socket
        skc_socket = [Socket socket];
        [skc_socket retain];
        
        //reset the parsing aparatus
        skc_incomingMessageBufferCursor = 0;
        skc_incomingMessageBufferExpectedLength = -1;
		skc_socket_readBufferCursor = 0;
		skc_socket_numLastBytesRead = 0;
        
		skc_loopCount = 0;
		
		inVal0 = 0;
		inVal1 = 0;
		inVal2 = 0;
		inVal3 = 0;
		
		last_inVal0 = 0;
		last_inVal1 = 0;
		last_inVal2 = 0;
		last_inVal3 = 0;

		outVal0 = 0;
		outVal1 = 0;
		outVal2 = 0;
		outVal3 = 0;

		last_outVal0 = 0;
		last_outVal1 = 0;
		last_outVal2 = 0;
		last_outVal3 = 0;
		
		[self skc_startLoop];
        
        // Display response in context textview
        NSLog(@"MainViewController: done enabling SketchServer connection");
        
        sketchServerEnabled = 1;
    } //if not enabled
} //enableSketchServer

- (void) skc_startLoop {
	[self skc_startLoopOnTimer];
	//[self skc_startLoopOnThread];
}
- (void) skc_stopLoop {
	[self skc_stopLoopOnTimer];
	//[self skc_stopLoopOnThread];
}
/************************************************/
- (void)skc_startLoopOnTimer {
        if (skc_socketTimer != NULL ) [self skc_stopLoop];
        //skc_socketTimer = [[NSTimer scheduledTimerWithTimeInterval: 5.0f
		if (iopackBoostEnabled == 1) {
			skc_socketTimer = [[NSTimer timerWithTimeInterval: kSketchServerPeriodBoosted
				target:self
				selector:@selector(skc_loop)
				userInfo:nil
				repeats: YES]
				retain];
		} else {
			skc_socketTimer = [[NSTimer timerWithTimeInterval: kSketchServerPeriod
				target:self
				selector:@selector(skc_loop)
				userInfo:nil
				repeats: YES]
				retain];
		}
			
		lastFireTime = 0.0f;
		[[NSRunLoop mainRunLoop] addTimer: skc_socketTimer forMode: NSDefaultRunLoopMode];
		
} //skc_startLoopOnTimer

- (void) skc_stopLoopOnTimer {
        [skc_socketTimer invalidate];
} //skc_stopLoopOnTimer

/************************************************/
- (void) skc_startLoopOnThread {
	[NSThread detachNewThreadSelector:@selector(skc_threadWorker)
		toTarget:self
		withObject:nil];
} //skc_startLoopOnThread

- (void) skc_stopLoopOnThread {
	//the thread will end automatically when sketchServerEnabled == 0
} //skc_stopLoopOnThread

- (void) skc_threadWorker {
	NSLog(@"skc_threadWorker: **** THIS APPLICATION IS NOW MULTI-THREADED ****");
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    while (sketchServerEnabled == 1) {
        //to run something on the main thread (like a UI update), use
        //[outputTextField1 performSelectorOnMainThread ... ];
		NSLog(@"skc_threadWorker: entering skc_loop");
		[self skc_loop];
		NSLog(@"skc_threadWorker: left skc_loop");
		[NSThread sleepForTimeInterval:kSketchServerPeriod];
    }

    [pool release];
}
/************************************************/

- (void)disableSketchServer {
    NSLog(@"MainViewController: disableSketchServer");
    if (sketchServerEnabled == 1) {
        NSLog(@"MainViewController: disabling SketchServer connection");
		[self skc_stopLoop];
        [skc_socket close];
        [skc_socket release];
        sketchServerEnabled = 0;
    } //if enabled
} //disableSketchServer

- (void) setSketchServerName: (NSString *)name {
	[self disableSensors];
	if ((name != NULL) && (name != nil)) {
		sketchServerName = name;
	} else {
		sketchServerName = @"";
	}
	[self enableSensors];
} //setSketchServerName

/*
 * returns the server address currently in use
 */
-(id)getSketchServerName {
    return sketchServerName;
}


/*
 * sets the state of flow control for the crurent connection
 */
- (void) setFlowControlState: (int)state {
	if (state == 1) {
		serverFlowControlEnabled = 1;
	} else {
		serverFlowControlEnabled = 0;
		serverFlowControlWaitForSetUntil = 0;
	}
}
/*
 * returns the state of flow control on the current server connection
 */
- (int) getFlowControlState {
	NSLog(@"getFlowControlState = %i", serverFlowControlEnabled);
	return serverFlowControlEnabled;
}

- (void) setIOPackBoostState: (int)state {
	if (state == 1) {
		iopackBoostEnabled = 1;
	} else {
		iopackBoostEnabled = 0;
	}
}
- (int) getIOPackBoostState {
	NSLog(@"getIOPackBoostState = %i", iopackBoostEnabled);
	return iopackBoostEnabled;
}

- (void)skc_loop {
	//NSLog(@"skc_loop Fire!");
	now = CFAbsoluteTimeGetCurrent();
	
    //NSLog(@"skc_loop Time since last fire is %f seconds ", (now - lastFireTime));
	lastFireTime = now;
	
    if ((skc_socketIsConnecting == NO) && ([skc_socket isConnected] == NO) && (sketchServerName != NULL) && (sketchServerName != nil)) {
		/*
		 * if we're not connected, try to do so:
		 */
		 
        NSLog(@"MainViewController: going to connect to host %@", sketchServerName);
        
        //try to connect the socket
        @try {
            [skc_socket close];
            [skc_socket release];
            
            skc_socket = [Socket socket];
            [skc_socket retain];
            [skc_socket setBlocking:NO];
            
            [skc_socket connectToHostName:sketchServerName port:1025];
            NSLog(@"MainViewController: connected to host");
        }
        @catch (id theException) {
            NSLog(@"Exception while trying to connect to sketch server: %@", theException);
            if ([[NSString stringWithFormat:@"%@", theException] isEqualToString: @"Socket: Connect failed: Operation now in progress"]) {
                skc_socketIsConnecting = YES;
            } else {
                skc_socketIsConnecting = NO;
            }
        }
		
    } else {
		/*
		 * ...or, do this if we're already connected:
		 */
		
		if ((skc_socketIsConnecting == YES) && ([skc_socket isConnected] == YES)) skc_socketIsConnecting = NO;
		
		//check if we need to read from the network socket
		if (
			([skc_socket isConnected] == YES)
			&&
			([skc_socket isReadable] == YES)
			&&
			(
				//we want to read if the socket is connected and one of these two conditions is true:
				(skc_socket_numLastBytesRead == 0) //no data in the buffer last time it was read
				||
				(skc_socket_readBufferCursor >= skc_socket_numLastBytesRead) //data in the buffer has all been processed
		)) {
			//NSLog(@"MainViewController: socket is readable, reading...");
			@try {
				skc_socket_numLastBytesRead = [skc_socket read];
				skc_socket_readBufferCursor = 0;
				//NSLog(@"MainViewController: Read %i bytes", skc_socket_numLastBytesRead);
				
			}
			@catch (id theException) {
				NSLog(@"Exception while trying to read sketch server: %@", theException);
				[skc_socket close];
			}
			
		} //if socket is connected and readable
		
		//check if there is data waiting to go to the sketch, and process it if there is
		if (skc_socket_numLastBytesRead > 0) [self skc_processInputBuffer];
		//skc_socket_readBufferCursor = skc_socket_numLastBytesRead; //fastest processing possible :)
		
		//check if the sketch is trying to send something
		if (skc_loopCount == kLoopsPerPollForIOPackOutput) {
			[self skc_pollSketchForIOPackOutput_withScanner];
			skc_loopCount = 0;
		} else {
			skc_loopCount++;
		}
		
		//if flow control is enabled, then send a GET message to the server
		if (
			(sketchServerEnabled == 1)
			&&
			(serverFlowControlEnabled == 1)
		) {
			now = CFAbsoluteTimeGetCurrent();
			if (now >= serverFlowControlWaitForSetUntil) {
				[self skc_sendGetMessage];
				serverFlowControlWaitForSetUntil = CFAbsoluteTimeGetCurrent() + kFlowControlWaitForSetTimeout;
			}
		}

	} //if connected
	
	now = CFAbsoluteTimeGetCurrent();
	//NSLog(@"skc_loop Loop ending, time spent was %f seconds ", (now - lastFireTime));
	
}  //skc_loop

- (void) skc_processInputBuffer {
	//NSLog(@"MainViewController.skc_processInputBuffer skc_socket_readBufferCursor=%i skc_socket_numLastBytesRead=%i", skc_socket_readBufferCursor, skc_socket_numLastBytesRead);
	for (;
		skc_socket_readBufferCursor < skc_socket_numLastBytesRead;
		skc_socket_readBufferCursor++
	) {
		//NSLog(@"MainViewController.skc_processInputBuffer LOOP skc_socket_readBufferCursor=%i skc_socket_numLastBytesRead=%i", skc_socket_readBufferCursor, skc_socket_numLastBytesRead);
		//there is some data in the buffer

		cin = (/*(char *)*/skc_socket.readBuffer)[skc_socket_readBufferCursor];

		if (cin == kSketchProtocol_setMessageOpcode) {
			//NSLog(@"GOT SET MESSAGE AT BYTE %i ", i);
			//found a set message, so reset the message buffer cursor and set the expected message length
			skc_incomingMessageBufferCursor = 0;
			skc_incomingMessageBufferExpectedLength = kSketchProtocol_setMessageLength;
		}
			
		//if there is still space left in the incoming message buffer, add this byte to it and advance the cursor
		if (skc_incomingMessageBufferCursor < skc_incomingMessageBufferExpectedLength) {
			//copy byte from the socket read buffer into the message buffer
			(/*(char *)*/skc_incomingMessageBuffer)[skc_incomingMessageBufferCursor] = cin;
			skc_incomingMessageBufferCursor++;
		}
		
		//when the incoming set message buffer fills...
		if (skc_incomingMessageBufferCursor == skc_incomingMessageBufferExpectedLength) {
			//NSLog(@"Message buffer has reached expected length!");
			//...process it
			if ((/*(char *)*/skc_incomingMessageBuffer)[ 0 ] //kSketchProtocol_messageOffsetOpcode
			== kSketchProtocol_setMessageOpcode ) {
				serverFlowControlWaitForSetUntil = 0;
				[self skc_decodeSetMessageFromBuffer];
				
				//update the measured iopack sampling rate
				now = CFAbsoluteTimeGetCurrent();
				actualIOPackSamplingRate += (1 / (now - lastIOPackSampleTime));
				actualIOPackSamplingRate /= 2;
				lastIOPackSampleTime = now;
				NSLog(@"Average sampling rate: %f", actualIOPackSamplingRate);
				
			}
			
			//...and reset the message buffer
			skc_incomingMessageBufferCursor = 0;
			skc_incomingMessageBufferExpectedLength = -1;
			
			//if we're not using flow control, stop processing the network buffer until
			//the next time the timer fires
			if (serverFlowControlEnabled == 0)
				return;
			
		} //if message buffer has reached expected length
		
	} //while more data in the socket buffer
	
} //skc_processInputBuffer

- (void) skc_decodeSetMessageFromBuffer {
    inVal0 = (((/*(char *)*/skc_incomingMessageBuffer)[ 1 ] & 0x0f) << 4)
            +
           ((/*(char *)*/skc_incomingMessageBuffer)[ 2 ] & 0x0f); 

    inVal1 = (((/*(char *)*/skc_incomingMessageBuffer)[ 3 ] & 0x0f) << 4)
            +
           ((/*(char *)*/skc_incomingMessageBuffer)[ 4 ] & 0x0f); 

    inVal2 = (((/*(char *)*/skc_incomingMessageBuffer)[ 5 ] & 0x0f) << 4)
            +
           ((/*(char *)*/skc_incomingMessageBuffer)[ 6 ] & 0x0f); 

    inVal3 = (((/*(char *)*/skc_incomingMessageBuffer)[ 7 ] & 0x0f) << 4)
            +
           ((/*(char *)*/skc_incomingMessageBuffer)[ 8 ] & 0x0f); 
    
	if ((last_inVal0 != inVal0) || (last_inVal1 != inVal1) || (last_inVal2 != inVal2) || (last_inVal3 != inVal3)) {
		//only update the sketch if the value has changed
        retainedJavaScriptCall = [NSString stringWithFormat:@"%@(%i, %i, %i, %i)",
            kSketchCallbackOnIOPack,
            inVal0,
            inVal1,
            inVal2,
            inVal3
            ];
		//NSLog(retainedJavaScriptCall);
		[webView stringByEvaluatingJavaScriptFromString:retainedJavaScriptCall];

		last_inVal0 = inVal0;
		last_inVal1 = inVal1;
		last_inVal2 = inVal2;
		last_inVal3 = inVal3;
	}
} //skc_decodeSetMessageFromBuffer

- (void) skc_pollSketchForIOPackOutput_withScanner {
    //NSLog(@"skc_pollSketchForIOPackOutput_withScanner");
    retainedJavaScriptCall = [NSString stringWithFormat:@"%@()", kSketchIOPackOutPollFcn];
    retainedSendValuesStr = [webView stringByEvaluatingJavaScriptFromString:retainedJavaScriptCall];
    if ([retainedSendValuesStr length] > 0) {
        //NSLog(@"Sketch wants to set %@", retainedSendValuesStr);
        
		skc_sketchPollingScanner = [NSScanner scannerWithString:retainedSendValuesStr];
		
        @try {
            //convert the value string back into ints
            //skc_sketchPollingScanner = [NSScanner scannerWithString:[retainedSendValuesStr substringWithRange:NSMakeRange( 0, 3 )]];
			[skc_sketchPollingScanner setScanLocation:0];
            if ([skc_sketchPollingScanner scanInt:&outVal0] == NO) outVal0 = 0;

            //skc_sketchPollingScanner = [NSScanner scannerWithString:[retainedSendValuesStr substringWithRange:NSMakeRange( 4, 3 )]];
			[skc_sketchPollingScanner setScanLocation:4];
            if ([skc_sketchPollingScanner scanInt:&outVal1] == NO) outVal1 = 0;

            //skc_sketchPollingScanner = [NSScanner scannerWithString:[retainedSendValuesStr substringWithRange:NSMakeRange( 8, 3 )]];
			[skc_sketchPollingScanner setScanLocation:8];
            if ([skc_sketchPollingScanner scanInt:&outVal2] == NO) outVal2 = 0;

            //skc_sketchPollingScanner = [NSScanner scannerWithString:[retainedSendValuesStr substringWithRange:NSMakeRange( 12, 3 )]];
			[skc_sketchPollingScanner setScanLocation:12];
            if ([skc_sketchPollingScanner scanInt:&outVal3] == NO) outVal3 = 0;

			if (
				(sketchServerEnabled == 1)
			) {
				//only send the message if a value has changed
				if ((outVal0 != last_outVal0) || (outVal1 != last_outVal1) || (outVal2 != last_outVal2) || (outVal3 != last_outVal3)) {
					[self skc_sendSetMessage];

					last_outVal0 = outVal0;
					last_outVal1 = outVal1;
					last_outVal2 = outVal2;
					last_outVal3 = outVal3;
				}
			}
        }
        @catch (id theException) {
            NSLog(@"Exception while trying to convert values from sketch to ints: %@", theException);
        }
    }
} //skc_pollSketchForIOPackOutput_withScanner

- (void) skc_sendGetMessage {
    //NSLog(@"skc_sendGetMessage");
	(/*(char *)*/skc_outgoingMessageBuffer)[ 0 ] = kSketchProtocol_getMessageOpcode;

	if (
		([skc_socket isConnected] == YES)
		&&
		([skc_socket isWritable] == YES)
	) {
		[skc_socket writeData:[NSData dataWithBytesNoCopy: skc_outgoingMessageBuffer
					length: kSketchProtocol_getMessageLength
					freeWhenDone: NO ]];
	}
}
- (void) skc_sendSetMessage {
    //NSLog(@"skc_sendSetMessage %i %i %i %i", outVal0, outVal1, outVal2, outVal3);
    
    (/*(char *)*/skc_outgoingMessageBuffer)[ 0 ] = kSketchProtocol_setMessageOpcode; //kSketchProtocol_messageOffsetOpcode
    
    (/*(char *)*/skc_outgoingMessageBuffer)[ 1 ] = ((outVal0 >> 4) & 0x0F);
    (/*(char *)*/skc_outgoingMessageBuffer)[ 2 ] = (outVal0 & 0x0F);
    
    (/*(char *)*/skc_outgoingMessageBuffer)[ 3 ] = ((outVal1 >> 4) & 0x0F);
    (/*(char *)*/skc_outgoingMessageBuffer)[ 4 ] = (outVal1 & 0x0F);
    
    (/*(char *)*/skc_outgoingMessageBuffer)[ 5 ] = ((outVal2 >> 4) & 0x0F);
    (/*(char *)*/skc_outgoingMessageBuffer)[ 6 ] = (outVal2 & 0x0F);
    
    (/*(char *)*/skc_outgoingMessageBuffer)[ 7 ] = ((outVal3 >> 4) & 0x0F);
    (/*(char *)*/skc_outgoingMessageBuffer)[ 8 ] = (outVal3 & 0x0F);
    
	if (
		([skc_socket isConnected] == YES)
		&&
		([skc_socket isWritable] == YES)
	) {
		[skc_socket writeData:[NSData dataWithBytesNoCopy: skc_outgoingMessageBuffer
					length: kSketchProtocol_setMessageLength
					freeWhenDone: NO ]];
	}
        
} //skc_sendSetMessage

- (void)skc_allocMessageBuffer
{
    // Allocate readBuffer
    
    if ( skc_incomingMessageBuffer == NULL )
    {
        skc_incomingMessageBuffer = (char*) malloc(skc_incomingMessageBufferSize);
        if ( skc_incomingMessageBuffer == NULL )
            [NSException raise:@"skc_allocMessageBuffer malloc failed for incoming buffer" format:@"skc_allocMessageBuffer malloc failed for incoming buffer"];
    }
    if ( skc_outgoingMessageBuffer == NULL )
    {
        skc_outgoingMessageBuffer = (char*) malloc(skc_outgoingMessageBufferSize);
        if ( skc_outgoingMessageBuffer == NULL )
            [NSException raise:@"skc_allocMessageBuffer malloc failed for outgoing buffer" format:@"skc_allocMessageBuffer malloc failed for outgoing buffer"];
    }
}

/*******************************************************************************************************************/

// set up to receive accelerometer notifications
- (void)enableSensorAccelerometer {
    NSLog(@"MainViewController: enableSensorAccelerometer");
    if (sensorAccelerometerEnabled == 0) {
        NSLog(@"MainViewController: enableSensorLocation: enabling accelerometer...");
        [[UIAccelerometer sharedAccelerometer] setUpdateInterval:kAccelerometerPeriod];
        [[UIAccelerometer sharedAccelerometer] setDelegate:self];
        //make sure we don't do this more than once:
        sensorAccelerometerEnabled = 1;
    }
}
- (void)disableSensorAccelerometer {
    NSLog(@"MainViewController: disableSensorAccelerometer");
    if (sensorLocationEnabled == 1) {
        NSLog(@"MainViewController: enableSensorLocation: disabling accelerometer...");
        //sensorAccelerometerEnabled = 0;
    }
}
// receive notifications from the accelerometer
- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration {
	//DO NOT USE retainedJavaScriptCall HERE!!!
    NSString* javaScriptCall = [NSString stringWithFormat:@"%@(%f, %f, %f)",
        kSketchCallbackOnAccelerate,
        acceleration.x,
        acceleration.y,
        acceleration.z
        ];
    //NSLog(javaScriptCall);
    [webView stringByEvaluatingJavaScriptFromString:javaScriptCall];
}
// process audio amplitude info
- (void)audioAmplitudeTimer:(NSTimer*)timer {
    [self audioAmplitude:am_io.peakAmp];
}
- (void) audioAmplitude:(UInt8)amp {
	//DO NOT USE retainedJavaScriptCall HERE!!!
    NSString* javaScriptCall = [NSString stringWithFormat:@"%@(%d)",
                                kSketchCallbackOnAudioAmplitude,
                                amp
                                ];
    //NSLog(javaScriptCall);
    [webView stringByEvaluatingJavaScriptFromString:javaScriptCall];
}

/*******************************************************************************************************************/

// set up to receive core location notifications
- (void)enableSensorLocation {
    NSLog(@"MainViewController: enableSensorLocation");
    if (sensorLocationEnabled == 0) {
        NSLog(@"MainViewController: enableSensorLocation: enabling location sensor...");
        locationManager = [[CLLocationManager alloc] init];
        locationManager.delegate = self;
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
        locationManager.distanceFilter = 500;
        //start updating
        [locationManager startUpdatingLocation];
        //make sure we don't do this more than once:
        sensorLocationEnabled = 1;
    }
}
- (void)disableSensorLocation {
    NSLog(@"MainViewController: disableSensorLocation");
    if (sensorLocationEnabled == 1) {
        NSLog(@"MainViewController: enableSensorLocation: disabling location sensor...");
        //sensorLocationEnabled = 0;
    }
}
// Receives notifications from CoreLocation, delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
		   fromLocation:(CLLocation *)oldLocation
{
	NSLog(@"Location updated");
    // If it's a relatively recent event, turn off updates to save power
    NSDate* eventDate = newLocation.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (abs(howRecent) < 5.0) {
        [manager stopUpdatingLocation];
        
		//DO NOT USE retainedJavaScriptCall HERE!!!
        NSString* javaScriptCall = [NSString stringWithFormat:@"%@(%f, %f, %f)",
            kSketchCallbackOnLocation,
            newLocation.coordinate.latitude,
            newLocation.coordinate.longitude,
            newLocation.altitude
            ];
        //NSLog(javaScriptCall);
        [webView stringByEvaluatingJavaScriptFromString:javaScriptCall];
    }
    // else skip the event and process the next one.
}

//location manager failed with an error
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
	NSLog(@"locationManager error: %@", error.localizedDescription);
}

/*******************************************************************************************************************/

//clean up instance
- (void)dealloc {
	NSLog(@"MainViewController dealloc");
	
	[self disableSensors];
	
	[webView release];
	[locationManager release];

    if ( skc_incomingMessageBuffer )
    {
        free(skc_incomingMessageBuffer);
        skc_incomingMessageBuffer = NULL;
    }
    if ( skc_outgoingMessageBuffer )
    {
        free(skc_outgoingMessageBuffer);
        skc_outgoingMessageBuffer = NULL;
    }

	[[NSUserDefaults standardUserDefaults] setObject:@"OK" forKey:kUserDefaultsKey_LastShutdownStatus];

	[super dealloc];
}

@end
